﻿//-------------------------------------------------------------------
//	Copyright (c) 2012 Fedotov I.V.
//	All rights reserved.
//-------------------------------------------------------------------
/*
	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program. If not, see http://www.gnu.org/licenses/.

	Project SVN page 
*/

#ifndef __IDLIST_H__
#define __IDLIST_H__

#include <stdio.h>
#include <string.h>
#include <map>

#include "../datacontainerbase.h"
#include "../filecontainer.h"
#include "../../sptr.h"

class UString;
class LangPairString;
class LangSelector;
class LangString;
class Languages;
class Position;
class SizeXY;
class Limit;
class Transformation;
//MACROS017:class #;

template <class T> class IDList : public DataContainerBase{

private:
	//Тип списка с шаблоном например CT_ID_LIST_USTRING
  ContainerType ct;

	SPtr<map<__int64, SPtr<T>>> ID_List;

	void setCTTypeAtT(){
	  ct=CT_INVALID;
    if(typeid(T)==typeid(UString))ct=CT_ID_LIST_USTRING;
    if(typeid(T)==typeid(LangPairString))ct=CT_ID_LIST_LANG_PAIR_USTRING;
    if(typeid(T)==typeid(LangSelector))ct=CT_ID_LIST_LANG_SELECTOR;
    if(typeid(T)==typeid(LangString))ct=CT_ID_LIST_LANG_USTRING;
		if(typeid(T)==typeid(Languages))ct=CT_ID_LIST_LANGUAGES;
		if(typeid(T)==typeid(Position))ct=CT_ID_LIST_POSITION;
    if(typeid(T)==typeid(SizeXY))ct=CT_ID_LIST_SIZE_XY;
		if(typeid(T)==typeid(Limit))ct=CT_ID_LIST_LIMIT;
		if(typeid(T)==typeid(Transformation))ct=CT_ID_LIST_TRANSFORMATION;
		//MACROS018:if(typeid(T)==typeid(#))ct=#;
		
	}

	friend int getObjsUStringID_ListT_AtGloblResManager(map<__int64, SPtr<UString>> *mapIDs);
	friend int getObjsLangPairStringID_ListT_AtGloblResManager(map<__int64, SPtr<LangPairString>> *mapIDs);
	friend int getObjsLangSelectorID_ListT_AtGloblResManager(map<__int64, SPtr<LangSelector>> *mapIDs);
	friend int getObjsLangStringID_ListT_AtGloblResManager(map<__int64, SPtr<LangString>> *mapIDs);
	friend int getObjsLanguagesID_ListT_AtGloblResManager(map<__int64, SPtr<Languages>> *mapIDs);
	friend int getObjsPositionID_ListT_AtGloblResManager(map<__int64, SPtr<Position>> *mapIDs);
	friend int getObjsSizeXYID_ListT_AtGloblResManager(map<__int64, SPtr<SizeXY>> *mapIDs);
	friend int getObjsLimitID_ListT_AtGloblResManager(map<__int64, SPtr<Limit>> *mapIDs);
	friend int getObjsTransformationID_ListT_AtGloblResManager(map<__int64, SPtr<Transformation>> *mapIDs);
	//MACROS019:friend int getObjs#ID_ListT_AtGloblResManager(map<__int64, SPtr<#>> *mapIDs);

public:

int checkAndSetObjectsAtIDs(){

  if(typeid(T)==typeid(UString))return getObjsUStringID_ListT_AtGloblResManager((map<__int64,SPtr<UString>> *)ID_List.p());
	if(typeid(T)==typeid(LangPairString))return getObjsLangPairStringID_ListT_AtGloblResManager((map<__int64,SPtr<LangPairString>> *)ID_List.p());
	if(typeid(T)==typeid(LangSelector))return getObjsLangSelectorID_ListT_AtGloblResManager((map<__int64,SPtr<LangSelector>> *)ID_List.p());
	if(typeid(T)==typeid(LangString))return getObjsLangStringID_ListT_AtGloblResManager((map<__int64,SPtr<LangString>> *)ID_List.p());
	if(typeid(T)==typeid(Languages))return getObjsLanguagesID_ListT_AtGloblResManager((map<__int64,SPtr<Languages>> *)ID_List.p());
	if(typeid(T)==typeid(Position))return getObjsPositionID_ListT_AtGloblResManager((map<__int64,SPtr<Position>> *)ID_List.p());
	if(typeid(T)==typeid(SizeXY))return getObjsSizeXYID_ListT_AtGloblResManager((map<__int64,SPtr<SizeXY>> *)ID_List.p());
	if(typeid(T)==typeid(Limit))return getObjsLimitID_ListT_AtGloblResManager((map<__int64,SPtr<Limit>> *)ID_List.p());
	if(typeid(T)==typeid(Transformation))return getObjsTransformationID_ListT_AtGloblResManager((map<__int64,SPtr<Transformation>> *)ID_List.p());
	//MACROS020:if(typeid(T)==typeid(#))return getObjs#ID_ListT_AtGloblResManager((map<__int64,SPtr<#>> *)ID_List.p());

  return -1;
}

IDList():DataContainerBase(){
  setCTTypeAtT();
}

IDList(__int64 _ID):DataContainerBase(_ID){
  setCTTypeAtT();
}

~IDList(){
	
}

//Не следует добавлять элементы списка, получив объект
//таким образом (для этого следует пользоваться функцией ...)
//Удаление элементов корректно.
SPtr<map<__int64, SPtr<T>>> getAndCheckObjectMap(){
	checkAndSetObjectsAtIDs();
	return ID_List;
}

/*
//Если не указывать параметр val, то поиск объекта будет произведен
//в ResourseManager. Объект уже должен быть в нем.
//Идентификатор _id должен совпадать с идентификатором в val
int addToIDList(__int64 _id, SPtr<T> *val=NULL){
	if(val!=NULL){
		if(_id!=(*val).p()->getID())return -1;
    ID_List.p()->insert(pair<__int64, SPtr<T>>(_id, *val));
		return 0;
	}
	else{
		SPtr<T> sp;
		sp.p()->setID(0);
		D_List.p()->insert(pair<__int64, SPtr<T>>(_id, sp));
    checkAndSetObjectsAtIDs();
	}
}
*/

int addToIDList(SPtr<T> val){
  ID_List.p()->insert(pair<__int64, SPtr<T>>(val.p()->getID(), val));
	return 0;
}

void clearIDList(){
  ID_List.p()->clear();
}

void setIDListType(ContainerType _ct){
  ct=_ct;
}

long parse(SPtr<FileContainer> _inFileContainer,long _offsetInData){

  long dataSize;
	char *dataBuf=NULL;
  
  if(preParse(_inFileContainer,_offsetInData,&dataBuf,&dataSize)!=1)return -1;
	if(dataBuf==NULL)return -1;

	//Разбор контейнера для конкретного типа (этого объекта):
	//if(_inFileContainer.p()->getContainerType()!=ct)return -3;
	if(dataSize<4)return -4;
	setID(getFileContainer().p()->getID());

	__int64 id_val;
  long id_Count;
	long i;
	
	memcpy((void *)(&id_Count),(void *)dataBuf,4);
	
	ID_List.p()->clear();
	if(id_Count<=0 || id_Count*8+4>dataSize)return -5;

	for(i=0;i<id_Count;i++){
		SPtr<T> sp(SPTR_ALLOC_ON_CALL);
	  memcpy((void *)(&id_val),(void *)(dataBuf+i*8+4),8);
		ID_List.p()->insert(pair<__int64,SPtr<T>>(id_val, sp));
			//push_back(id_val);
	}

	return id_Count*8+4;

}

long parse(){
	if(getFileContainer().isNULLPtr())return -1;
	if(getFileContainer().p()->getContainerType()!=ct)return -3;
	return parse(getFileContainer(),0);
}

int join(){

	if(preJoin()!=1)return -1;
	if(checkAndSetObjectsAtIDs()<0)return -2;

	//сборка данных в контейнер:
	getFileContainer().p()->setContainerType(ct);
	getFileContainer().p()->setID(getID());
	
	char* data;
	long size;
	__int64 val;
	long i=0;

	size=ID_List.p()->size()*8+4;
	data=new(_NORMAL_BLOCK, __FILE__, __LINE__) char[size];

	((long *)data)[0]=ID_List.p()->size();
	
	map<__int64, SPtr<T>>::iterator iter;
	for(iter=ID_List.p()->begin();iter!=ID_List.p()->end();iter++){
		val=(*iter).first;
		memcpy((void *)(data+i*8+4),(void *)(&val),8);
		i++;
	}

	getFileContainer().p()->setDataCopy(data,size);
	delete [] data;
	return 0;

}








/*
  IDList();
	IDList(__int64 _ID);
	~IDList();

	long parse();
	long parse(SPtr<FileContainer> _inFileContainer,long _offsetInData);
	int join();

	int setObjectsAtIDs();
*/
};


#endif